# coding: utf-8
import os
import sys
import logging
import pygame
import re

try:
    __file__
except NameError as e:
    from whereis import mymain
    rootdir = mymain()
else:
    rootdir = os.path.dirname(os.path.dirname(__file__))
sys.path.insert(0, rootdir)
from lib.bashlog import getlogger
from lib.tracemore import get_exc_plus
from lib.config import Config
from lib.circle import Circle
from lib.inputer import Inputer
from lib.wrap import Wrapper
from lib.sprite import Sprite
from lib.sprite import Group
from lib import events
from lib import color
sys.path.pop(0)

logger = logging.getLogger('wordson.topic')
cfg = Config()

class Text(Sprite):
    '''The topic user need to anwser'''
    def __init__(self, width=None, text='', line_interval=0):
        super(Text, self).__init__()

        self._width = 70 if width is None else width
        self.wrapper = Wrapper(width=self._width)
        self.text = text
        self.line_interval = line_interval

        self.image = self.fontsuf()
        self.rect = self.image.get_rect()

    def fontsuf(self, text=None, color=color.black):
        if text is None:
            text = self.text
        textline = self.wrapper.wrap(text).splitlines()
        textsurf = list(map(lambda t: self.font.render(t, True, color, None), textline))

        max_height = 0
        max_width = 0
        for each in textsurf:
            rect = each.get_rect()
            max_height = max(max_height, rect.height)
            max_width = max(max_width, rect.width)

        surf_height = max((max_height+self.line_interval) * len(textsurf) - self.line_interval, 0)
        surf_width = max_width

        surf = pygame.Surface((surf_width, surf_height), flags=pygame.SRCALPHA)
        start = 0
        while textsurf:
            font_suf = textsurf.pop(0)
            surf.blit(font_suf, (0, start))
            start += (max_height + self.line_interval)
        return surf

    @property
    def font(self):    # lazy load. Cannot use before init pygame
        return cfg.font

    @property
    def width(self):
        return self._width
    @width.setter
    def width(self, value):
        self._width = value
        self.wrapper = value

class Title(Text):
    def __init__(self, text=''):
        width = cfg.topic_len
        hspace = cfg.topic_hspace
        super(Title, self).__init__(width, text, line_interval=hspace)
        self.rect.x = cfg.topic_x
        self.rect.y = cfg.topic_y

    def set(self, text):
        self.text = text
        topleft = self.rect.topleft
        self.image = self.fontsuf()
        self.rect = self.image.get_rect()
        self.rect.topleft = topleft

        logger.debug('%s at %s', text, self.rect)


class Option(Sprite):
    def __init__(self, text=''):
        self._rawtext = text
        self.text = Text(cfg.option_len, text)
        super(Option, self).__init__()
        self.circle = Circle()

        rectt = self.text.rect
        rectc = self.circle.rect

        # rectc.x = x
        # rectc.y = y
        rectt.left = rectc.right + 3
        rectt.top = rectc.top

        self.rect = pygame.Rect(0, 0, 0, 0)
        self._update()

        self.refresh = False
        self.bind_key = None


    @property
    def rawtext(self):
        return self._rawtext
    @rawtext.setter
    def rawtext(self, value):
        self._rawtext = value
        # save old rect position
        oldrect = self.text.rect
        left = oldrect.left
        top = oldrect.top
        # refresh the font image
        self.text = Text(cfg.option_len, value)
        self.text.image = self.text.fontsuf()
        # restore rect position
        rect = self.text.image.get_rect()
        rect.left = left
        rect.top = top
        self.text.rect = rect
        self.refresh = True

    def handle(self, event):
        if self.text.handle(event):
            logger.debug('%s handled', event)
            return True
        if self.circle.handle(event):
            logger.debug('%s handled by circle', event)
            return True
        if event.type == pygame.MOUSEMOTION:
            pos = event.pos
            collided = self.rect.collidepoint(pos)
            if collided != self.circle.DRAW:
                logger.debug('collided %s, %s', collided, self)
                self.circle.DRAW = collided
        elif event.type == pygame.KEYDOWN:
            if event.key == self.bind_key:
                logger.info('key currect %s', event.unicode)
                self.circle.DRAW = True
            else:
                self.circle.DRAW = False


    def collidepoint(self, pos):
        for rect in (self.circle.rect, self.text.rect):
            if rect.collidepoint(pos):
                return True
        return False

    def update(self, time):
        if not self.circle.DONE:
            self.refresh = True    # the circle is drawing. Need calc image
        self.text.update(time)
        self.circle.update(time)

        if self.refresh:
            self._update()

    def _update(self):
        '''join the image together'''
        t = self.text
        c = self.circle
        rt = t.rect
        rc = c.rect

        width = rt.width + rc.width
        height = max(rt.height, rc.height)

        self.rect.size = (width, height)
        img = pygame.Surface((width, height), flags=pygame.SRCALPHA)
        img.blit(c.image, (0, 0))
        img.blit(t.image, (rc.width, 0))
        self.image = img



    def draw(self, surface):
        self.text.draw(surface)
        self.circle.draw(surface)

    def __str__(self):
        result = super(Option, self).__str__()
        return ''.join((result[:-1], 'bind_key=', pygame.key.name(self.bind_key), '>'))


class Topic(Group):
    SELECT = True
    def __init__(self):
        super(Topic, self).__init__()
        t = Title()
        self.title = t
        self.options = []
        for key in (pygame.K_a, pygame.K_b, pygame.K_c, pygame.K_d):
            opt = Option()
            opt.bind_key = key
            self.options.append(opt)
        self.inputer = Inputer()
        self.rect = pygame.Rect(0, 0, 0, 0)
        self.add(self.title)
        self.refresh_sprites()

    def set(self, title, detail, select):
        select = bool(select)
        if select != self.SELECT:
            self.SELECT = select
            self.refresh_sprites()

        self.title.set(title)
        if select:
            for text, opt in zip(detail, self.options):
                opt.rawtext = text
        else:
            self.inputer.clear()
            self.inputer.anwser = detail
        self.rearange()

    def refresh_sprites(self):
        logger.debug('refresh sprites: select=%s', self.SELECT)
        if self.SELECT:
            kill = (self.inputer, )
            add = self.options
        else:
            kill = self.options
            add = (self.inputer, )

        for each in kill:
            each.kill()

        for each in add:
            self.add(each)



    def rearange(self):
        '''adjust the rect of each sprite'''
        rectt = self.title.rect
        top = rectt.bottom
        left = rectt.left
        centerx = rectt.centerx

        recti = self.inputer.rect
        recti.centerx = centerx
        recti.top = top

        for each in self.options:
            recto = each.rect
            recto.left = left
            recto.top = top
            top += recto.height


if __name__ == '__main__':
    getlogger(logger, logging.DEBUG)

    pygame.init()
    pygame.key.set_repeat(cfg.key_repeat_delay, cfg.key_repeat_interval)
    screen = pygame.display.set_mode(cfg.screen)


    run = True
    clock = pygame.time.Clock()
    # title = Title("""I'm using python with pygame and trying to get the width of text. The pygame documentation says to use pygame.font.Font.size(). 但我有点不明白应该使用哪个函数。我一直收到`TypeError: descriptor 'size' requires a 'pygame.font.Font' object but received a 'str'`的错误。""")
    # title.set("Test")
    # title.image = title.fontsuf()
    # opt = Option(0, 0, 'Test')
    # cir = opt.circle
    topic = Topic()
    topic.set("Test title", "Test Inputer", False)
    topic.set("I'm using python with pygame and trying to get the width of text. The pygame documentation says to use pygame.font.Font.size(). 但我有点不明白应该使用哪个函数。我一直收到`TypeError: descriptor 'size' requires a 'pygame.font.Font' object but received a 'str'`的错误。",
              "A.重启;B.关机;C.还原;D.换用Ubuntu系统啊Ubuntu啊这年头谁还用Windows写代码啊".split(';'),
              True)
                # "...",
                # False)

    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            # opt.handle(event)
            topic.handle(event)

        inter = clock.tick(cfg.tick)
        # opt.update(inter)
        topic.update(inter)
        screen.fill(color.white)
        # title.draw(screen)
        # opt.draw(screen)
        topic.draw(screen)
        # topic.title.draw(screen)
        pygame.display.flip()

    pygame.quit()
